package org.example.controller;

import io.avaje.inject.Component;
import io.ebean.PagedList;
import io.jooby.Context;
import io.jooby.MediaType;
import io.jooby.annotation.*;
import jakarta.inject.Inject;
import org.example.domain.User;
import org.example.param.UserQueryParam;
import org.example.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@Component
@Path("/users") // Base path for all methods in this controller
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    private final UserRepository userRepository;

    @Inject // Avaje Inject will provide the UserRepository instance
    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GET
    @Produces(MediaType.JSON) // Specify response content type
    public List<User> getAllUsers(@QueryParam String name) {
        log.info("GET /users request received:" + name);
        return userRepository.findAll(name);
    }

    @GET("/page")
    @Produces(MediaType.JSON) // Specify response content type
    public PagedList<User> getPage(Context ctx) {
        UserQueryParam userQueryParam = ctx.query(UserQueryParam.class);
        log.info("GET /users request received:" + userQueryParam);
        return userRepository.findPageList(userQueryParam);
    }


    @GET("/{id}")
    @Produces(MediaType.JSON)
    public User getUserById(@PathParam long id, Context ctx) {
        log.info("GET /users/{} request received", id);
        return userRepository.findById(id)
                .orElseThrow(() -> {
                    log.warn("User not found: {}", id);
                    return new io.jooby.exception.NotFoundException("User not found with ID: " + id);
                });
    }

    @POST
    @Consumes(MediaType.JSON) // Specify request body content type
    @Produces(MediaType.JSON)
    public Context createUser(Context ctx) throws Exception {
        User newUser = ctx.body().to(User.class); // Deserialize JSON body to User object
        log.info("POST /users request received with user: {}", newUser.getName());
        // Basic validation check example (consider using bean validation framework)
        if (newUser.getName() == null || newUser.getName().trim().isEmpty() ||
                newUser.getEmail() == null || newUser.getEmail().trim().isEmpty()) {
            return ctx.setResponseCode(io.jooby.StatusCode.BAD_REQUEST)
                    .render("Name and Email are required.");
        }
        User savedUser = userRepository.save(newUser);
        log.info("User created with ID: {}", savedUser.getId());
        return ctx.setResponseCode(io.jooby.StatusCode.CREATED) // Set HTTP 201 Created
                .render(savedUser); // Render the created user as JSON response
    }

    @PUT("/{id}")
    @Consumes(MediaType.JSON)
    @Produces(MediaType.JSON)
    public User updateUser(@PathParam long id, Context ctx) throws Exception {
        User userUpdates = ctx.body().to(User.class);
        log.info("PUT /users/{} request received for user: {}", id, userUpdates.getName());
        // Note: The ID from the path parameter should be trusted over any ID in the body
        // The repository logic handles fetching the existing user by ID first.
        return userRepository.update(id, userUpdates)
                .orElseThrow(() -> {
                    log.warn("User not found for update: {}", id);
                    return new io.jooby.exception.NotFoundException("User not found with ID: " + id + " for update");
                });
    }

    @DELETE("/{id}")
    public Context deleteUser(@PathParam long id, Context ctx) {
        log.info("DELETE /users/{} request received", id);
        boolean deleted = userRepository.deleteById(id);
        if (deleted) {
            log.info("User deleted successfully: {}", id);
            return ctx.setResponseCode(io.jooby.StatusCode.NO_CONTENT); // HTTP 204 No Content
        } else {
            log.warn("User not found for deletion: {}", id);
            throw new io.jooby.exception.NotFoundException("User not found with ID: " + id + " for deletion");
        }
    }
}